home *** CD-ROM | disk | FTP | other *** search
/ Introduction to 3D Game …ogramming with DirectX 12 / Introduction-to-3D-Game-Programming-with-DirectX-12.ISO / Code.Textures / Chapter 8 Lighting / LitWaves / LitWavesApp.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2016-03-02  |  26.7 KB  |  800 lines

  1. //***************************************************************************************
  2. // LitWavesApp.cpp by Frank Luna (C) 2015 All Rights Reserved.
  3. //
  4. // Use arrow keys to move light positions.
  5. //
  6. //***************************************************************************************
  7.  
  8. #include "../../Common/d3dApp.h"
  9. #include "../../Common/MathHelper.h"
  10. #include "../../Common/UploadBuffer.h"
  11. #include "../../Common/GeometryGenerator.h"
  12. #include "FrameResource.h"
  13. #include "Waves.h"
  14.  
  15. using Microsoft::WRL::ComPtr;
  16. using namespace DirectX;
  17. using namespace DirectX::PackedVector;
  18.  
  19. #pragma comment(lib, "d3dcompiler.lib")
  20. #pragma comment(lib, "D3D12.lib")
  21.  
  22. const int gNumFrameResources = 3;
  23.  
  24. // Lightweight structure stores parameters to draw a shape.  This will
  25. // vary from app-to-app.
  26. struct RenderItem
  27. {
  28.     RenderItem() = default;
  29.  
  30.     // World matrix of the shape that describes the object's local space
  31.     // relative to the world space, which defines the position, orientation,
  32.     // and scale of the object in the world.
  33.     XMFLOAT4X4 World = MathHelper::Identity4x4();
  34.  
  35.     XMFLOAT4X4 TexTransform = MathHelper::Identity4x4();
  36.  
  37.     // Dirty flag indicating the object data has changed and we need to update the constant buffer.
  38.     // Because we have an object cbuffer for each FrameResource, we have to apply the
  39.     // update to each FrameResource.  Thus, when we modify obect data we should set 
  40.     // NumFramesDirty = gNumFrameResources so that each frame resource gets the update.
  41.     int NumFramesDirty = gNumFrameResources;
  42.  
  43.     // Index into GPU constant buffer corresponding to the ObjectCB for this render item.
  44.     UINT ObjCBIndex = -1;
  45.  
  46.     Material* Mat = nullptr;
  47.     MeshGeometry* Geo = nullptr;
  48.  
  49.     // Primitive topology.
  50.     D3D12_PRIMITIVE_TOPOLOGY PrimitiveType = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
  51.  
  52.     // DrawIndexedInstanced parameters.
  53.     UINT IndexCount = 0;
  54.     UINT StartIndexLocation = 0;
  55.     int BaseVertexLocation = 0;
  56. };
  57.  
  58. enum class RenderLayer : int
  59. {
  60.     Opaque = 0,
  61.     Count
  62. };
  63.  
  64. class LitWavesApp : public D3DApp
  65. {
  66. public:
  67.     LitWavesApp(HINSTANCE hInstance);
  68.     LitWavesApp(const LitWavesApp& rhs) = delete;
  69.     LitWavesApp& operator=(const LitWavesApp& rhs) = delete;
  70.     ~LitWavesApp();
  71.  
  72.     virtual bool Initialize()override;
  73.  
  74. private:
  75.     virtual void OnResize()override;
  76.     virtual void Update(const GameTimer& gt)override;
  77.     virtual void Draw(const GameTimer& gt)override;
  78.  
  79.     virtual void OnMouseDown(WPARAM btnState, int x, int y)override;
  80.     virtual void OnMouseUp(WPARAM btnState, int x, int y)override;
  81.     virtual void OnMouseMove(WPARAM btnState, int x, int y)override;
  82.  
  83.     void OnKeyboardInput(const GameTimer& gt);
  84.     void UpdateCamera(const GameTimer& gt);
  85.     void UpdateObjectCBs(const GameTimer& gt);
  86.     void UpdateMaterialCBs(const GameTimer& gt);
  87.     void UpdateMainPassCB(const GameTimer& gt);
  88.     void UpdateWaves(const GameTimer& gt);
  89.  
  90.     void BuildRootSignature();
  91.     void BuildShadersAndInputLayout();
  92.     void BuildLandGeometry();
  93.     void BuildWavesGeometryBuffers();
  94.     void BuildPSOs();
  95.     void BuildFrameResources();
  96.     void BuildMaterials();
  97.     void BuildRenderItems();
  98.     void DrawRenderItems(ID3D12GraphicsCommandList* cmdList, const std::vector<RenderItem*>& ritems);
  99.  
  100.     float GetHillsHeight(float x, float z)const;
  101.     XMFLOAT3 GetHillsNormal(float x, float z)const;
  102.  
  103. private:
  104.  
  105.     std::vector<std::unique_ptr<FrameResource>> mFrameResources;
  106.     FrameResource* mCurrFrameResource = nullptr;
  107.     int mCurrFrameResourceIndex = 0;
  108.  
  109.     UINT mCbvSrvDescriptorSize = 0;
  110.  
  111.     ComPtr<ID3D12RootSignature> mRootSignature = nullptr;
  112.  
  113.     std::unordered_map<std::string, std::unique_ptr<MeshGeometry>> mGeometries;
  114.     std::unordered_map<std::string, std::unique_ptr<Material>> mMaterials;
  115.     std::unordered_map<std::string, std::unique_ptr<Texture>> mTextures;
  116.     std::unordered_map<std::string, ComPtr<ID3DBlob>> mShaders;
  117.     std::unordered_map<std::string, ComPtr<ID3D12PipelineState>> mPSOs;
  118.  
  119.     std::vector<D3D12_INPUT_ELEMENT_DESC> mInputLayout;
  120.  
  121.     RenderItem* mWavesRitem = nullptr;
  122.  
  123.     // List of all the render items.
  124.     std::vector<std::unique_ptr<RenderItem>> mAllRitems;
  125.  
  126.     // Render items divided by PSO.
  127.     std::vector<RenderItem*> mRitemLayer[(int)RenderLayer::Count];
  128.  
  129.     std::unique_ptr<Waves> mWaves;
  130.  
  131.     PassConstants mMainPassCB;
  132.  
  133.     XMFLOAT3 mEyePos = { 0.0f, 0.0f, 0.0f };
  134.     XMFLOAT4X4 mView = MathHelper::Identity4x4();
  135.     XMFLOAT4X4 mProj = MathHelper::Identity4x4();
  136.  
  137.     float mTheta = 1.5f*XM_PI;
  138.     float mPhi = XM_PIDIV2 - 0.1f;
  139.     float mRadius = 50.0f;
  140.  
  141.     float mSunTheta = 1.25f*XM_PI;
  142.     float mSunPhi = XM_PIDIV4;
  143.  
  144.     POINT mLastMousePos;
  145. };
  146.  
  147. int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE prevInstance,
  148.     PSTR cmdLine, int showCmd)
  149. {
  150.     // Enable run-time memory check for debug builds.
  151. #if defined(DEBUG) | defined(_DEBUG)
  152.     _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
  153. #endif
  154.  
  155.     try
  156.     {
  157.         LitWavesApp theApp(hInstance);
  158.         if(!theApp.Initialize())
  159.             return 0;
  160.  
  161.         return theApp.Run();
  162.     }
  163.     catch(DxException& e)
  164.     {
  165.         MessageBox(nullptr, e.ToString().c_str(), L"HR Failed", MB_OK);
  166.         return 0;
  167.     }
  168. }
  169.  
  170. LitWavesApp::LitWavesApp(HINSTANCE hInstance)
  171.     : D3DApp(hInstance)
  172. {
  173. }
  174.  
  175. LitWavesApp::~LitWavesApp()
  176. {
  177.     if(md3dDevice != nullptr)
  178.         FlushCommandQueue();
  179. }
  180.  
  181. bool LitWavesApp::Initialize()
  182. {
  183.     if(!D3DApp::Initialize())
  184.         return false;
  185.  
  186.     // Reset the command list to prep for initialization commands.
  187.     ThrowIfFailed(mCommandList->Reset(mDirectCmdListAlloc.Get(), nullptr));
  188.  
  189.     // Get the increment size of a descriptor in this heap type.  This is hardware specific, so we have
  190.     // to query this information.
  191.     mCbvSrvDescriptorSize = md3dDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
  192.  
  193.     mWaves = std::make_unique<Waves>(128, 128, 1.0f, 0.03f, 4.0f, 0.2f);
  194.  
  195.     BuildRootSignature();
  196.     BuildShadersAndInputLayout();
  197.     BuildLandGeometry();
  198.     BuildWavesGeometryBuffers();
  199.     BuildMaterials();
  200.     BuildRenderItems();
  201.     BuildRenderItems();
  202.     BuildFrameResources();
  203.     BuildPSOs();
  204.  
  205.     // Execute the initialization commands.
  206.     ThrowIfFailed(mCommandList->Close());
  207.     ID3D12CommandList* cmdsLists[] = { mCommandList.Get() };
  208.     mCommandQueue->ExecuteCommandLists(_countof(cmdsLists), cmdsLists);
  209.  
  210.     // Wait until initialization is complete.
  211.     FlushCommandQueue();
  212.  
  213.     return true;
  214. }
  215.  
  216. void LitWavesApp::OnResize()
  217. {
  218.     D3DApp::OnResize();
  219.  
  220.     // The window resized, so update the aspect ratio and recompute the projection matrix.
  221.     XMMATRIX P = XMMatrixPerspectiveFovLH(0.25f*MathHelper::Pi, AspectRatio(), 1.0f, 1000.0f);
  222.     XMStoreFloat4x4(&mProj, P);
  223. }
  224.  
  225. void LitWavesApp::Update(const GameTimer& gt)
  226. {
  227.     OnKeyboardInput(gt);
  228.     UpdateCamera(gt);
  229.  
  230.     // Cycle through the circular frame resource array.
  231.     mCurrFrameResourceIndex = (mCurrFrameResourceIndex + 1) % gNumFrameResources;
  232.     mCurrFrameResource = mFrameResources[mCurrFrameResourceIndex].get();
  233.  
  234.     // Has the GPU finished processing the commands of the current frame resource?
  235.     // If not, wait until the GPU has completed commands up to this fence point.
  236.     if(mCurrFrameResource->Fence != 0 && mFence->GetCompletedValue() < mCurrFrameResource->Fence)
  237.     {
  238.         HANDLE eventHandle = CreateEventEx(nullptr, false, false, EVENT_ALL_ACCESS);
  239.         ThrowIfFailed(mFence->SetEventOnCompletion(mCurrFrameResource->Fence, eventHandle));
  240.         WaitForSingleObject(eventHandle, INFINITE);
  241.         CloseHandle(eventHandle);
  242.     }
  243.  
  244.     UpdateObjectCBs(gt);
  245.     UpdateMaterialCBs(gt);
  246.     UpdateMainPassCB(gt);
  247.     UpdateWaves(gt);
  248. }
  249.  
  250. void LitWavesApp::Draw(const GameTimer& gt)
  251. {
  252.     auto cmdListAlloc = mCurrFrameResource->CmdListAlloc;
  253.  
  254.     // Reuse the memory associated with command recording.
  255.     // We can only reset when the associated command lists have finished execution on the GPU.
  256.     ThrowIfFailed(cmdListAlloc->Reset());
  257.  
  258.     // A command list can be reset after it has been added to the command queue via ExecuteCommandList.
  259.     // Reusing the command list reuses memory.
  260.     ThrowIfFailed(mCommandList->Reset(cmdListAlloc.Get(), mPSOs["opaque"].Get()));
  261.  
  262.     mCommandList->RSSetViewports(1, &mScreenViewport);
  263.     mCommandList->RSSetScissorRects(1, &mScissorRect);
  264.  
  265.     // Indicate a state transition on the resource usage.
  266.     mCommandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(CurrentBackBuffer(),
  267.         D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET));
  268.  
  269.     // Clear the back buffer and depth buffer.
  270.     mCommandList->ClearRenderTargetView(CurrentBackBufferView(), Colors::LightSteelBlue, 0, nullptr);
  271.     mCommandList->ClearDepthStencilView(DepthStencilView(), D3D12_CLEAR_FLAG_DEPTH | D3D12_CLEAR_FLAG_STENCIL, 1.0f, 0, 0, nullptr);
  272.  
  273.     // Specify the buffers we are going to render to.
  274.     mCommandList->OMSetRenderTargets(1, &CurrentBackBufferView(), true, &DepthStencilView());
  275.  
  276.     mCommandList->SetGraphicsRootSignature(mRootSignature.Get());
  277.  
  278.     auto passCB = mCurrFrameResource->PassCB->Resource();
  279.     mCommandList->SetGraphicsRootConstantBufferView(2, passCB->GetGPUVirtualAddress());
  280.  
  281.     DrawRenderItems(mCommandList.Get(), mRitemLayer[(int)RenderLayer::Opaque]);
  282.  
  283.     // Indicate a state transition on the resource usage.
  284.     mCommandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(CurrentBackBuffer(),
  285.         D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT));
  286.  
  287.     // Done recording commands.
  288.     ThrowIfFailed(mCommandList->Close());
  289.  
  290.     // Add the command list to the queue for execution.
  291.     ID3D12CommandList* cmdsLists[] = { mCommandList.Get() };
  292.     mCommandQueue->ExecuteCommandLists(_countof(cmdsLists), cmdsLists);
  293.  
  294.     // Swap the back and front buffers
  295.     ThrowIfFailed(mSwapChain->Present(0, 0));
  296.     mCurrBackBuffer = (mCurrBackBuffer + 1) % SwapChainBufferCount;
  297.  
  298.     // Advance the fence value to mark commands up to this fence point.
  299.     mCurrFrameResource->Fence = ++mCurrentFence;
  300.  
  301.     // Add an instruction to the command queue to set a new fence point. 
  302.     // Because we are on the GPU timeline, the new fence point won't be 
  303.     // set until the GPU finishes processing all the commands prior to this Signal().
  304.     mCommandQueue->Signal(mFence.Get(), mCurrentFence);
  305. }
  306.  
  307. void LitWavesApp::OnMouseDown(WPARAM btnState, int x, int y)
  308. {
  309.     mLastMousePos.x = x;
  310.     mLastMousePos.y = y;
  311.  
  312.     SetCapture(mhMainWnd);
  313. }
  314.  
  315. void LitWavesApp::OnMouseUp(WPARAM btnState, int x, int y)
  316. {
  317.     ReleaseCapture();
  318. }
  319.  
  320. void LitWavesApp::OnMouseMove(WPARAM btnState, int x, int y)
  321. {
  322.     if((btnState & MK_LBUTTON) != 0)
  323.     {
  324.         // Make each pixel correspond to a quarter of a degree.
  325.         float dx = XMConvertToRadians(0.25f*static_cast<float>(x - mLastMousePos.x));
  326.         float dy = XMConvertToRadians(0.25f*static_cast<float>(y - mLastMousePos.y));
  327.  
  328.         // Update angles based on input to orbit camera around box.
  329.         mTheta += dx;
  330.         mPhi += dy;
  331.  
  332.         // Restrict the angle mPhi.
  333.         mPhi = MathHelper::Clamp(mPhi, 0.1f, MathHelper::Pi - 0.1f);
  334.     }
  335.     else if((btnState & MK_RBUTTON) != 0)
  336.     {
  337.         // Make each pixel correspond to 0.2 unit in the scene.
  338.         float dx = 0.2f*static_cast<float>(x - mLastMousePos.x);
  339.         float dy = 0.2f*static_cast<float>(y - mLastMousePos.y);
  340.  
  341.         // Update the camera radius based on input.
  342.         mRadius += dx - dy;
  343.  
  344.         // Restrict the radius.
  345.         mRadius = MathHelper::Clamp(mRadius, 5.0f, 150.0f);
  346.     }
  347.  
  348.     mLastMousePos.x = x;
  349.     mLastMousePos.y = y;
  350. }
  351.  
  352. void LitWavesApp::OnKeyboardInput(const GameTimer& gt)
  353. {
  354.     const float dt = gt.DeltaTime();
  355.  
  356.     if(GetAsyncKeyState(VK_LEFT) & 0x8000)
  357.         mSunTheta -= 1.0f*dt;
  358.  
  359.     if(GetAsyncKeyState(VK_RIGHT) & 0x8000)
  360.         mSunTheta += 1.0f*dt;
  361.  
  362.     if(GetAsyncKeyState(VK_UP) & 0x8000)
  363.         mSunPhi -= 1.0f*dt;
  364.  
  365.     if(GetAsyncKeyState(VK_DOWN) & 0x8000)
  366.         mSunPhi += 1.0f*dt;
  367.  
  368.     mSunPhi = MathHelper::Clamp(mSunPhi, 0.1f, XM_PIDIV2);
  369. }
  370.  
  371. void LitWavesApp::UpdateCamera(const GameTimer& gt)
  372. {
  373.     // Convert Spherical to Cartesian coordinates.
  374.     mEyePos.x = mRadius*sinf(mPhi)*cosf(mTheta);
  375.     mEyePos.z = mRadius*sinf(mPhi)*sinf(mTheta);
  376.     mEyePos.y = mRadius*cosf(mPhi);
  377.  
  378.     // Build the view matrix.
  379.     XMVECTOR pos = XMVectorSet(mEyePos.x, mEyePos.y, mEyePos.z, 1.0f);
  380.     XMVECTOR target = XMVectorZero();
  381.     XMVECTOR up = XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f);
  382.  
  383.     XMMATRIX view = XMMatrixLookAtLH(pos, target, up);
  384.     XMStoreFloat4x4(&mView, view);
  385. }
  386.  
  387. void LitWavesApp::UpdateObjectCBs(const GameTimer& gt)
  388. {
  389.     auto currObjectCB = mCurrFrameResource->ObjectCB.get();
  390.     for(auto& e : mAllRitems)
  391.     {
  392.         // Only update the cbuffer data if the constants have changed.  
  393.         // This needs to be tracked per frame resource.
  394.         if(e->NumFramesDirty > 0)
  395.         {
  396.             XMMATRIX world = XMLoadFloat4x4(&e->World);
  397.             XMMATRIX texTransform = XMLoadFloat4x4(&e->TexTransform);
  398.  
  399.             ObjectConstants objConstants;
  400.             XMStoreFloat4x4(&objConstants.World, XMMatrixTranspose(world));
  401.  
  402.             currObjectCB->CopyData(e->ObjCBIndex, objConstants);
  403.  
  404.             // Next FrameResource need to be updated too.
  405.             e->NumFramesDirty--;
  406.         }
  407.     }
  408. }
  409.  
  410. void LitWavesApp::UpdateMaterialCBs(const GameTimer& gt)
  411. {
  412.     auto currMaterialCB = mCurrFrameResource->MaterialCB.get();
  413.     for(auto& e : mMaterials)
  414.     {
  415.         // Only update the cbuffer data if the constants have changed.  If the cbuffer
  416.         // data changes, it needs to be updated for each FrameResource.
  417.         Material* mat = e.second.get();
  418.         if(mat->NumFramesDirty > 0)
  419.         {
  420.             XMMATRIX matTransform = XMLoadFloat4x4(&mat->MatTransform);
  421.  
  422.             MaterialConstants matConstants;
  423.             matConstants.DiffuseAlbedo = mat->DiffuseAlbedo;
  424.             matConstants.FresnelR0 = mat->FresnelR0;
  425.             matConstants.Roughness = mat->Roughness;
  426.  
  427.             currMaterialCB->CopyData(mat->MatCBIndex, matConstants);
  428.  
  429.             // Next FrameResource need to be updated too.
  430.             mat->NumFramesDirty--;
  431.         }
  432.     }
  433. }
  434.  
  435. void LitWavesApp::UpdateMainPassCB(const GameTimer& gt)
  436. {
  437.     XMMATRIX view = XMLoadFloat4x4(&mView);
  438.     XMMATRIX proj = XMLoadFloat4x4(&mProj);
  439.  
  440.     XMMATRIX viewProj = XMMatrixMultiply(view, proj);
  441.     XMMATRIX invView = XMMatrixInverse(&XMMatrixDeterminant(view), view);
  442.     XMMATRIX invProj = XMMatrixInverse(&XMMatrixDeterminant(proj), proj);
  443.     XMMATRIX invViewProj = XMMatrixInverse(&XMMatrixDeterminant(viewProj), viewProj);
  444.  
  445.     XMStoreFloat4x4(&mMainPassCB.View, XMMatrixTranspose(view));
  446.     XMStoreFloat4x4(&mMainPassCB.InvView, XMMatrixTranspose(invView));
  447.     XMStoreFloat4x4(&mMainPassCB.Proj, XMMatrixTranspose(proj));
  448.     XMStoreFloat4x4(&mMainPassCB.InvProj, XMMatrixTranspose(invProj));
  449.     XMStoreFloat4x4(&mMainPassCB.ViewProj, XMMatrixTranspose(viewProj));
  450.     XMStoreFloat4x4(&mMainPassCB.InvViewProj, XMMatrixTranspose(invViewProj));
  451.     mMainPassCB.EyePosW = mEyePos;
  452.     mMainPassCB.RenderTargetSize = XMFLOAT2((float)mClientWidth, (float)mClientHeight);
  453.     mMainPassCB.InvRenderTargetSize = XMFLOAT2(1.0f / mClientWidth, 1.0f / mClientHeight);
  454.     mMainPassCB.NearZ = 1.0f;
  455.     mMainPassCB.FarZ = 1000.0f;
  456.     mMainPassCB.TotalTime = gt.TotalTime();
  457.     mMainPassCB.DeltaTime = gt.DeltaTime();
  458.     mMainPassCB.AmbientLight = { 0.25f, 0.25f, 0.35f, 1.0f };
  459.  
  460.     XMVECTOR lightDir = -MathHelper::SphericalToCartesian(1.0f, mSunTheta, mSunPhi);
  461.  
  462.     XMStoreFloat3(&mMainPassCB.Lights[0].Direction, lightDir);
  463.     mMainPassCB.Lights[0].Strength = { 1.0f, 1.0f, 0.9f };
  464.  
  465.     auto currPassCB = mCurrFrameResource->PassCB.get();
  466.     currPassCB->CopyData(0, mMainPassCB);
  467. }
  468.  
  469. void LitWavesApp::UpdateWaves(const GameTimer& gt)
  470. {
  471.     // Every quarter second, generate a random wave.
  472.     static float t_base = 0.0f;
  473.     if((mTimer.TotalTime() - t_base) >= 0.25f)
  474.     {
  475.         t_base += 0.25f;
  476.  
  477.         int i = MathHelper::Rand(4, mWaves->RowCount() - 5);
  478.         int j = MathHelper::Rand(4, mWaves->ColumnCount() - 5);
  479.  
  480.         float r = MathHelper::RandF(0.2f, 0.5f);
  481.  
  482.         mWaves->Disturb(i, j, r);
  483.     }
  484.  
  485.     // Update the wave simulation.
  486.     mWaves->Update(gt.DeltaTime());
  487.  
  488.     // Update the wave vertex buffer with the new solution.
  489.     auto currWavesVB = mCurrFrameResource->WavesVB.get();
  490.     for(int i = 0; i < mWaves->VertexCount(); ++i)
  491.     {
  492.         Vertex v;
  493.  
  494.         v.Pos = mWaves->Position(i);
  495.         v.Normal = mWaves->Normal(i);
  496.  
  497.         currWavesVB->CopyData(i, v);
  498.     }
  499.  
  500.     // Set the dynamic VB of the wave renderitem to the current frame VB.
  501.     mWavesRitem->Geo->VertexBufferGPU = currWavesVB->Resource();
  502. }
  503.  
  504. void LitWavesApp::BuildRootSignature()
  505. {
  506.     // Root parameter can be a table, root descriptor or root constants.
  507.     CD3DX12_ROOT_PARAMETER slotRootParameter[3];
  508.  
  509.     // Create root CBV.
  510.     slotRootParameter[0].InitAsConstantBufferView(0);
  511.     slotRootParameter[1].InitAsConstantBufferView(1);
  512.     slotRootParameter[2].InitAsConstantBufferView(2);
  513.  
  514.     // A root signature is an array of root parameters.
  515.     CD3DX12_ROOT_SIGNATURE_DESC rootSigDesc(3, slotRootParameter, 0, nullptr, D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT);
  516.  
  517.     // create a root signature with a single slot which points to a descriptor range consisting of a single constant buffer
  518.     ComPtr<ID3DBlob> serializedRootSig = nullptr;
  519.     ComPtr<ID3DBlob> errorBlob = nullptr;
  520.     HRESULT hr = D3D12SerializeRootSignature(&rootSigDesc, D3D_ROOT_SIGNATURE_VERSION_1,
  521.         serializedRootSig.GetAddressOf(), errorBlob.GetAddressOf());
  522.  
  523.     if(errorBlob != nullptr)
  524.     {
  525.         ::OutputDebugStringA((char*)errorBlob->GetBufferPointer());
  526.     }
  527.     ThrowIfFailed(hr);
  528.  
  529.     ThrowIfFailed(md3dDevice->CreateRootSignature(
  530.         0,
  531.         serializedRootSig->GetBufferPointer(),
  532.         serializedRootSig->GetBufferSize(),
  533.         IID_PPV_ARGS(mRootSignature.GetAddressOf())));
  534. }
  535.  
  536. void LitWavesApp::BuildShadersAndInputLayout()
  537. {
  538.     mShaders["standardVS"] = d3dUtil::CompileShader(L"Shaders\\Default.hlsl", nullptr, "VS", "vs_5_0");
  539.     mShaders["opaquePS"] = d3dUtil::CompileShader(L"Shaders\\Default.hlsl", nullptr, "PS", "ps_5_0");
  540.  
  541.     mInputLayout =
  542.     {
  543.         { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
  544.         { "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }
  545.     };
  546. }
  547.  
  548. void LitWavesApp::BuildLandGeometry()
  549. {
  550.     GeometryGenerator geoGen;
  551.     GeometryGenerator::MeshData grid = geoGen.CreateGrid(160.0f, 160.0f, 50, 50);
  552.  
  553.     //
  554.     // Extract the vertex elements we are interested and apply the height function to
  555.     // each vertex.  In addition, color the vertices based on their height so we have
  556.     // sandy looking beaches, grassy low hills, and snow mountain peaks.
  557.     //
  558.  
  559.     std::vector<Vertex> vertices(grid.Vertices.size());
  560.     for(size_t i = 0; i < grid.Vertices.size(); ++i)
  561.     {
  562.         auto& p = grid.Vertices[i].Position;
  563.         vertices[i].Pos = p;
  564.         vertices[i].Pos.y = GetHillsHeight(p.x, p.z);
  565.         vertices[i].Normal = GetHillsNormal(p.x, p.z);
  566.     }
  567.  
  568.     const UINT vbByteSize = (UINT)vertices.size() * sizeof(Vertex);
  569.  
  570.     std::vector<std::uint16_t> indices = grid.GetIndices16();
  571.     const UINT ibByteSize = (UINT)indices.size() * sizeof(std::uint16_t);
  572.  
  573.     auto geo = std::make_unique<MeshGeometry>();
  574.     geo->Name = "landGeo";
  575.  
  576.     ThrowIfFailed(D3DCreateBlob(vbByteSize, &geo->VertexBufferCPU));
  577.     CopyMemory(geo->VertexBufferCPU->GetBufferPointer(), vertices.data(), vbByteSize);
  578.  
  579.     ThrowIfFailed(D3DCreateBlob(ibByteSize, &geo->IndexBufferCPU));
  580.     CopyMemory(geo->IndexBufferCPU->GetBufferPointer(), indices.data(), ibByteSize);
  581.  
  582.     geo->VertexBufferGPU = d3dUtil::CreateDefaultBuffer(md3dDevice.Get(),
  583.         mCommandList.Get(), vertices.data(), vbByteSize, geo->VertexBufferUploader);
  584.  
  585.     geo->IndexBufferGPU = d3dUtil::CreateDefaultBuffer(md3dDevice.Get(),
  586.         mCommandList.Get(), indices.data(), ibByteSize, geo->IndexBufferUploader);
  587.  
  588.     geo->VertexByteStride = sizeof(Vertex);
  589.     geo->VertexBufferByteSize = vbByteSize;
  590.     geo->IndexFormat = DXGI_FORMAT_R16_UINT;
  591.     geo->IndexBufferByteSize = ibByteSize;
  592.  
  593.     SubmeshGeometry submesh;
  594.     submesh.IndexCount = (UINT)indices.size();
  595.     submesh.StartIndexLocation = 0;
  596.     submesh.BaseVertexLocation = 0;
  597.  
  598.     geo->DrawArgs["grid"] = submesh;
  599.  
  600.     mGeometries["landGeo"] = std::move(geo);
  601. }
  602.  
  603. void LitWavesApp::BuildWavesGeometryBuffers()
  604. {
  605.     std::vector<std::uint16_t> indices(3 * mWaves->TriangleCount()); // 3 indices per face
  606.     assert(mWaves->VertexCount() < 0x0000ffff);
  607.  
  608.     // Iterate over each quad.
  609.     int m = mWaves->RowCount();
  610.     int n = mWaves->ColumnCount();
  611.     int k = 0;
  612.     for(int i = 0; i < m - 1; ++i)
  613.     {
  614.         for(int j = 0; j < n - 1; ++j)
  615.         {
  616.             indices[k] = i*n + j;
  617.             indices[k + 1] = i*n + j + 1;
  618.             indices[k + 2] = (i + 1)*n + j;
  619.  
  620.             indices[k + 3] = (i + 1)*n + j;
  621.             indices[k + 4] = i*n + j + 1;
  622.             indices[k + 5] = (i + 1)*n + j + 1;
  623.  
  624.             k += 6; // next quad
  625.         }
  626.     }
  627.  
  628.     UINT vbByteSize = mWaves->VertexCount()*sizeof(Vertex);
  629.     UINT ibByteSize = (UINT)indices.size()*sizeof(std::uint16_t);
  630.  
  631.     auto geo = std::make_unique<MeshGeometry>();
  632.     geo->Name = "waterGeo";
  633.  
  634.     // Set dynamically.
  635.     geo->VertexBufferCPU = nullptr;
  636.     geo->VertexBufferGPU = nullptr;
  637.  
  638.     ThrowIfFailed(D3DCreateBlob(ibByteSize, &geo->IndexBufferCPU));
  639.     CopyMemory(geo->IndexBufferCPU->GetBufferPointer(), indices.data(), ibByteSize);
  640.  
  641.     geo->IndexBufferGPU = d3dUtil::CreateDefaultBuffer(md3dDevice.Get(),
  642.         mCommandList.Get(), indices.data(), ibByteSize, geo->IndexBufferUploader);
  643.  
  644.     geo->VertexByteStride = sizeof(Vertex);
  645.     geo->VertexBufferByteSize = vbByteSize;
  646.     geo->IndexFormat = DXGI_FORMAT_R16_UINT;
  647.     geo->IndexBufferByteSize = ibByteSize;
  648.  
  649.     SubmeshGeometry submesh;
  650.     submesh.IndexCount = (UINT)indices.size();
  651.     submesh.StartIndexLocation = 0;
  652.     submesh.BaseVertexLocation = 0;
  653.  
  654.     geo->DrawArgs["grid"] = submesh;
  655.  
  656.     mGeometries["waterGeo"] = std::move(geo);
  657. }
  658.  
  659. void LitWavesApp::BuildPSOs()
  660. {
  661.     D3D12_GRAPHICS_PIPELINE_STATE_DESC opaquePsoDesc;
  662.  
  663.     //
  664.     // PSO for opaque objects.
  665.     //
  666.     ZeroMemory(&opaquePsoDesc, sizeof(D3D12_GRAPHICS_PIPELINE_STATE_DESC));
  667.     opaquePsoDesc.InputLayout = { mInputLayout.data(), (UINT)mInputLayout.size() };
  668.     opaquePsoDesc.pRootSignature = mRootSignature.Get();
  669.     opaquePsoDesc.VS =
  670.     {
  671.         reinterpret_cast<BYTE*>(mShaders["standardVS"]->GetBufferPointer()),
  672.         mShaders["standardVS"]->GetBufferSize()
  673.     };
  674.     opaquePsoDesc.PS =
  675.     {
  676.         reinterpret_cast<BYTE*>(mShaders["opaquePS"]->GetBufferPointer()),
  677.         mShaders["opaquePS"]->GetBufferSize()
  678.     };
  679.     opaquePsoDesc.RasterizerState = CD3DX12_RASTERIZER_DESC(D3D12_DEFAULT);
  680.     opaquePsoDesc.BlendState = CD3DX12_BLEND_DESC(D3D12_DEFAULT);
  681.     opaquePsoDesc.DepthStencilState = CD3DX12_DEPTH_STENCIL_DESC(D3D12_DEFAULT);
  682.     opaquePsoDesc.SampleMask = UINT_MAX;
  683.     opaquePsoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
  684.     opaquePsoDesc.NumRenderTargets = 1;
  685.     opaquePsoDesc.RTVFormats[0] = mBackBufferFormat;
  686.     opaquePsoDesc.SampleDesc.Count = m4xMsaaState ? 4 : 1;
  687.     opaquePsoDesc.SampleDesc.Quality = m4xMsaaState ? (m4xMsaaQuality - 1) : 0;
  688.     opaquePsoDesc.DSVFormat = mDepthStencilFormat;
  689.     ThrowIfFailed(md3dDevice->CreateGraphicsPipelineState(&opaquePsoDesc, IID_PPV_ARGS(&mPSOs["opaque"])));
  690. }
  691.  
  692. void LitWavesApp::BuildFrameResources()
  693. {
  694.     for(int i = 0; i < gNumFrameResources; ++i)
  695.     {
  696.         mFrameResources.push_back(std::make_unique<FrameResource>(md3dDevice.Get(),
  697.             1, (UINT)mAllRitems.size(), (UINT)mMaterials.size(), mWaves->VertexCount()));
  698.     }
  699. }
  700.  
  701. void LitWavesApp::BuildMaterials()
  702. {
  703.     auto grass = std::make_unique<Material>();
  704.     grass->Name = "grass";
  705.     grass->MatCBIndex = 0;
  706.     grass->DiffuseAlbedo = XMFLOAT4(0.2f, 0.6f, 0.2f, 1.0f);
  707.     grass->FresnelR0 = XMFLOAT3(0.01f, 0.01f, 0.01f);
  708.     grass->Roughness = 0.125f;
  709.  
  710.     // This is not a good water material definition, but we do not have all the rendering
  711.     // tools we need (transparency, environment reflection), so we fake it for now.
  712.     auto water = std::make_unique<Material>();
  713.     water->Name = "water";
  714.     water->MatCBIndex = 1;
  715.     water->DiffuseAlbedo = XMFLOAT4(0.0f, 0.2f, 0.6f, 1.0f);
  716.     water->FresnelR0 = XMFLOAT3(0.1f, 0.1f, 0.1f);
  717.     water->Roughness = 0.0f;
  718.  
  719.     mMaterials["grass"] = std::move(grass);
  720.     mMaterials["water"] = std::move(water);
  721. }
  722.  
  723. void LitWavesApp::BuildRenderItems()
  724. {
  725.     auto wavesRitem = std::make_unique<RenderItem>();
  726.     wavesRitem->World = MathHelper::Identity4x4();
  727.     wavesRitem->ObjCBIndex = 0;
  728.     wavesRitem->Mat = mMaterials["water"].get();
  729.     wavesRitem->Geo = mGeometries["waterGeo"].get();
  730.     wavesRitem->PrimitiveType = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
  731.     wavesRitem->IndexCount = wavesRitem->Geo->DrawArgs["grid"].IndexCount;
  732.     wavesRitem->StartIndexLocation = wavesRitem->Geo->DrawArgs["grid"].StartIndexLocation;
  733.     wavesRitem->BaseVertexLocation = wavesRitem->Geo->DrawArgs["grid"].BaseVertexLocation;
  734.  
  735.     mWavesRitem = wavesRitem.get();
  736.  
  737.     mRitemLayer[(int)RenderLayer::Opaque].push_back(wavesRitem.get());
  738.  
  739.     auto gridRitem = std::make_unique<RenderItem>();
  740.     gridRitem->World = MathHelper::Identity4x4();
  741.     gridRitem->ObjCBIndex = 1;
  742.     gridRitem->Mat = mMaterials["grass"].get();
  743.     gridRitem->Geo = mGeometries["landGeo"].get();
  744.     gridRitem->PrimitiveType = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
  745.     gridRitem->IndexCount = gridRitem->Geo->DrawArgs["grid"].IndexCount;
  746.     gridRitem->StartIndexLocation = gridRitem->Geo->DrawArgs["grid"].StartIndexLocation;
  747.     gridRitem->BaseVertexLocation = gridRitem->Geo->DrawArgs["grid"].BaseVertexLocation;
  748.  
  749.     mRitemLayer[(int)RenderLayer::Opaque].push_back(gridRitem.get());
  750.  
  751.     mAllRitems.push_back(std::move(wavesRitem));
  752.     mAllRitems.push_back(std::move(gridRitem));
  753. }
  754.  
  755. void LitWavesApp::DrawRenderItems(ID3D12GraphicsCommandList* cmdList, const std::vector<RenderItem*>& ritems)
  756. {
  757.     UINT objCBByteSize = d3dUtil::CalcConstantBufferByteSize(sizeof(ObjectConstants));
  758.     UINT matCBByteSize = d3dUtil::CalcConstantBufferByteSize(sizeof(MaterialConstants));
  759.  
  760.     auto objectCB = mCurrFrameResource->ObjectCB->Resource();
  761.     auto matCB = mCurrFrameResource->MaterialCB->Resource();
  762.  
  763.     // For each render item...
  764.     for(size_t i = 0; i < ritems.size(); ++i)
  765.     {
  766.         auto ri = ritems[i];
  767.  
  768.         cmdList->IASetVertexBuffers(0, 1, &ri->Geo->VertexBufferView());
  769.         cmdList->IASetIndexBuffer(&ri->Geo->IndexBufferView());
  770.         cmdList->IASetPrimitiveTopology(ri->PrimitiveType);
  771.  
  772.         D3D12_GPU_VIRTUAL_ADDRESS objCBAddress = objectCB->GetGPUVirtualAddress() + ri->ObjCBIndex*objCBByteSize;
  773.         D3D12_GPU_VIRTUAL_ADDRESS matCBAddress = matCB->GetGPUVirtualAddress() + ri->Mat->MatCBIndex*matCBByteSize;
  774.  
  775.         cmdList->SetGraphicsRootConstantBufferView(0, objCBAddress);
  776.         cmdList->SetGraphicsRootConstantBufferView(1, matCBAddress);
  777.  
  778.         cmdList->DrawIndexedInstanced(ri->IndexCount, 1, ri->StartIndexLocation, ri->BaseVertexLocation, 0);
  779.     }
  780. }
  781.  
  782. float LitWavesApp::GetHillsHeight(float x, float z)const
  783. {
  784.     return 0.3f*(z*sinf(0.1f*x) + x*cosf(0.1f*z));
  785. }
  786.  
  787. XMFLOAT3 LitWavesApp::GetHillsNormal(float x, float z)const
  788. {
  789.     // n = (-df/dx, 1, -df/dz)
  790.     XMFLOAT3 n(
  791.         -0.03f*z*cosf(0.1f*x) - 0.3f*cosf(0.1f*z),
  792.         1.0f,
  793.         -0.3f*sinf(0.1f*x) + 0.03f*x*sinf(0.1f*z));
  794.  
  795.     XMVECTOR unitNormal = XMVector3Normalize(XMLoadFloat3(&n));
  796.     XMStoreFloat3(&n, unitNormal);
  797.  
  798.     return n;
  799. }
  800.